// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

 module counter2
 #(                                                     // ================= Parameters ==============
       parameter MAX_COUNT = 100                          // maximum number of clock cycles to count;
 )                                                      // iSetCnt should be smaller than this one.   
 (
                                                        // ================= Inputs =================
       input    iClk,                               // clock signal
       input    iRst_n,                             // reset

       input    iCntRst_n,                        // synchronous reset
       input    iCntEn ,                           // counter iCntEn 
       input    iLoad,                              // iLoad MAX_COUNT internal register	  
       input    [logb2(MAX_COUNT) : 0] iSetCnt,    //	      	 

                                                        // ================= Outputs =================   
       output   oDone,                              // It is high when max count has been reached       
       output  reg [logb2(MAX_COUNT) : 0] oCntr          // Current value of the counter
                                                        // unsigned MAX_COUNT-bits variable
 );

   //+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
   // Returns the floor of the base 2 log of the "size" number, we use the return 
   // value as the MSB bit in vector size definitions. e.g.; we need 4 bits for the
   // number 13, we need a vector with an index from 3 to 0. 
   //
   // flogb2(from 8 to 15) = 3 
   // flogb2(from 7 to 4 ) = 2
   // flogb2(from 3 to 2 ) = 1   
   //+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     function automatic integer logb2 ( input integer  size );
         integer size_buf;
         begin
         size_buf =size;
         for( logb2 = -1; size_buf > 0; logb2 = logb2 + 1 )  size_buf = size_buf >> 1;
         end   
     endfunction
   //+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+



   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
   // We often need latches simply to store bits of information; 
   // save the value the counter need to reach to assert and output flag. 
   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
     reg [logb2(MAX_COUNT) : 0] rMaxCnt;
    
//   always_latch begin : max_value
     always @( posedge iClk or negedge iRst_n ) begin 
			 if (     !iRst_n          )   rMaxCnt   <= {{logb2(MAX_COUNT){1'b1}}, 1'b1};            // fills all bits of MAX_COUNT_oCntr with 1 
                else if( iLoad && !iCntEn )   rMaxCnt   <= iSetCnt; 
             else                          rMaxCnt   <= rMaxCnt; 
     end      
	  

   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
   // Increments the conter count in each clock cycle if the iCntEn signal is asserted  	  
   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
     always @( posedge iClk or negedge iRst_n ) begin 
 
            if (       !iRst_n      )              oCntr   <= 0; 
            else if(   !iCntRst_n )                oCntr   <= 0; 
            else 
            begin
						
                  if (     oCntr == rMaxCnt )      oCntr   <= oCntr;
                  else if( iCntEn              )   oCntr   <= oCntr + 1'b1;
                  else                             oCntr   <= oCntr;
            end		   
      end      


   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
   // Assert done signal once the max count value is reached
   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	 
     assign oDone  =  (oCntr == rMaxCnt)  ?  1'b1 : 1'b0;
	  

   //-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//-----//	

 endmodule
 